﻿using Core.AutoFacService.Attributes.InjectAttributes;
using Core.AutoFacService.Enums;
using Core.CacheService.Interface;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace Core.CacheService
{
    [Inject(lifetime: LifetimeEnum.Single)]
    public class RedisCache: ICache
    {
        private ConnectionMultiplexer Redis { get; set; }
        private IConfiguration Configuration { get; set; }
        private static readonly object Redislock=new object();
        private static string ConnectionString;
        private static int DefaultDB;

        public RedisCache(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        private ConnectionMultiplexer GetRedis()
        {
            if (Redis == null)
            {
                lock (Redislock)
                {
                    if (Redis == null)
                    {
                        var redisConfig = Configuration.GetSection("Redis");
                        ConnectionString = redisConfig.GetValue<string>("ConnectionString");
                        DefaultDB = redisConfig.GetValue<int?>("DefaultDB") ?? 0;
                        Redis = ConnectionMultiplexer.Connect(ConnectionString);
                    }
                }
            }
            return Redis;
        }
        private IDatabase GetDB()
        {
            return GetRedis().GetDatabase(DefaultDB);
        }

        public bool SetValue<T>(string key, T value)
        {
            return GetDB().StringSet(key, GetJson(value));
        }

        public bool SetValue<T>(string key, T value, int expires)
        {
            return GetDB().StringSet(key, GetJson(value),TimeSpan.FromSeconds(expires));
        }

        public T GetValue<T>(string key)
        {
            string json= GetDB().StringGet(key);
            if(json == null)
            {
                return default(T);
            }
            if (!typeof(T).IsValueType)
            {
                return JsonConvert.DeserializeObject<T>(json);
            }
            else
            {
                Type realType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
                object SafeValue = (json == null) ? null : Convert.ChangeType(json, realType);
                return (T)SafeValue;
            }
        }
        public object GetValue(string key, Type type)
        {
            string json = GetDB().StringGet(key);
            if (json == null)
            {
                if (Nullable.GetUnderlyingType(type) != null)
                {
                    return null;
                }
                return type.IsValueType ? Activator.CreateInstance(type) : null;
            }
            if (!type.IsValueType)
            {
                return JsonConvert.DeserializeObject(json,type);
            }
            else
            {
                Type realType = Nullable.GetUnderlyingType(type) ?? type;
                object SafeValue = (json == null) ? null : Convert.ChangeType(json, realType);
                return SafeValue;
            }
        }

        public bool Contains(string key)
        {
            return GetDB().KeyExists(key);
        }

        public bool TryGet<T>(string key, out T value)
        {
            if (Contains(key))
            {
                value = GetValue<T>(key);
                return true;
            }
            else
            {
                value = default;
                return false;
            }
            
        }

        public bool DeleteKey(string key)
        {
            return GetDB().KeyDelete(key);
        }

        public bool SetNotExists<T>(string key, T value, int expires)
        {
            string json = GetJson(value);
            return GetDB().StringSet(key, json,TimeSpan.FromSeconds(expires),When.NotExists,CommandFlags.None);
        }

        private string GetJson<T>(T value)
        {
            if (typeof(T).IsValueType)
            {
                return value.ToString();
            }
            else
            {
                return JsonConvert.SerializeObject(value);
            }
        }

       

        ///// <summary>
        ///// 增加/修改
        ///// </summary>
        ///// <param name="key"></param>
        ///// <param name="value"></param>
        ///// <returns></returns>
        //public bool SetValue(string key, string value)
        //{
        //    return db.StringSet(key, value);
        //}

        ///// <summary>
        ///// 查询
        ///// </summary>
        ///// <param name="key"></param>
        ///// <returns></returns>
        //public string GetValue(string key)
        //{
        //    return db.StringGet(key);
        //}

        ///// <summary>
        ///// 删除
        ///// </summary>
        ///// <param name="key"></param>
        ///// <returns></returns>
        //public bool DeleteKey(string key)
        //{

        //    return db.KeyDelete(key);
        //}


    }
}
